<template>
  <div class="poetry-detail">
    <sg-header @back="onBack">
      诗词详情
      <template #right><div></div></template>
    </sg-header>

    <div class="main">
      <div ref="wrapper" class="main-wrapper" @click="onClickPoetry" sg-scroll="vertical_stop">
        <poetry v-if="poetry" ref="poetry" :poetry="poetry" :isDetail="true"></poetry>
      </div>
    </div>

    <image-viewer
      v-if="poetry"
      v-model:visible="viewerVisible"
      :index="imageIndex"
      :images="images"
    ></image-viewer>

    <comment-input
      v-if="poetry"
      v-model:visible="commentVisible"
      :id="commentID"
      :typeUserId="commentTypeUserID"
      :toId="commentToID"
      :placeholder="commentTip"
      @ok="handleCommentOk"
    ></comment-input>

    <transition name="slide">
      <div v-if="poetry" v-show="menusVisible" class="right-menus">
        <div class="menu-item" @click="handleDropdown('praise', $event)">
          <div :class="{ 'is-praise': isPraise }">
            <i class="iconfont icon-like"></i>
          </div>
          <span>{{ $filters.numFilter(poetry.praiseTotal, true) }}</span>
        </div>
        <div class="menu-item" @click="handleDropdown('comment', $event)">
          <div>
            <i class="iconfont icon-message"></i>
          </div>
          <span>{{ $filters.numFilter(poetry.commentTotal, true) }}</span>
        </div>
        <div v-if="isSelfPoetry" class="menu-item" @click="handleDropdown('edit', $event)">
          <div>
            <i class="iconfont icon-edit"></i>
          </div>
        </div>
        <div v-if="isSelfPoetry" class="menu-item" @click="handleDropdown('delete', $event)">
          <div>
            <i class="iconfont icon-delete"></i>
          </div>
        </div>
      </div>
    </transition>

    <praise-anime
      v-if="praiseVisible"
      :id="praiseId"
      :from="praiseFromStyle"
      :to="praiseToStyle"
      @end="handleAnimeEnd"
    ></praise-anime>
  </div>
</template>

<script lang="ts">
import { defineComponent, defineAsyncComponent } from 'vue'
import { mapState } from 'pinia'
import { useAuthStore } from '@/store/index'
import { apiURL, apiGetData, apiPostData } from '@/api'
import { getItemIndex, getItemTypeIndex, getItemTypeObj } from '@/utils/dom'
import Cache from '@/store/cache'
import { PEOTRY } from '@/const'

export default defineComponent({
  name: 'PoetryDetail',

  components: {
    poetry: defineAsyncComponent(() => import('@/components/poetry-detail.vue')),
    'image-viewer': defineAsyncComponent(() => import('@/components/image-viewer.vue')),
    'comment-input': defineAsyncComponent(() => import('@/components/comment-input.vue')),
    'praise-anime': defineAsyncComponent(() => import('@/components/praise-anime.vue'))
  },

  data() {
    return {
      poetryID: '0',
      poetry: null as any,

      menusVisible: true,

      viewerVisible: false,
      images: [] as any[],
      imageIndex: 0,

      myPraiseComment: null as any,
      commentVisible: false,
      commentID: '0',
      commentTypeUserID: '0',
      commentToID: '0',
      commentTip: '请输入',

      praiseVisible: false,
      praiseId: 0,
      praiseFromStyle: {},
      praiseToStyle: {},
      praiseMap: {},

      praiseOffset: 0,
      commentOffset: 0,
      pageLimit: 20,

      praiseRequesting: false,
      previousTime: 0
    }
  },

  computed: {
    /**
     * @returns {Boolean} 返回是否为当前用户创建的诗词
     */
    isSelfPoetry() {
      const poetry = this.poetry
      return poetry && poetry.user && this.userID === (poetry.poetId || poetry.user.id)
    },

    /**
     * @returns {Boolean} 返回当前登录用户是否点赞当前诗词
     */
    isPraise() {
      return !!this.myPraiseComment
    },

    ...mapState(useAuthStore, {
      userID: 'userID',
      selfPublicInfo: 'selfPublicInfo'
    })
  },

  created() {
    window.poetryDetail = this
    this.checkRestorePageData()
  },

  beforeRouteUpdate(_to, _from, next) {
    this.savePageData()
    next()
    this.checkRestorePageData()
  },

  beforeRouteLeave(_to, _from, next) {
    this.savePageData()
    next()
  },

  methods: {
    onBack() {
      this.$router.go(-1)
    },

    savePageData() {
      Cache.PoetryPageCache.setData(this.poetryID, {
        poetry: this.poetry,
        praiseOffset: this.praiseOffset,
        commentOffset: this.commentOffset,
        scrollTop: (this.$refs.wrapper as any).scrollTop,
        myPraiseComment: this.myPraiseComment
      })
    },
    restorePageData() {
      const pageCacheData = Cache.PoetryPageCache.getData(this.poetryID)
      if (!pageCacheData) {
        return false
      }

      this.poetry = pageCacheData.poetry
      this.praiseOffset = pageCacheData.praiseOffset
      this.commentOffset = pageCacheData.commentOffset
      this.myPraiseComment = pageCacheData.myPraiseComment
      if (!this.myPraiseComment) {
        this.checkPraisePoetry()
      }

      this.$nextTick(() => {
        ;(this.$refs.wrapper as HTMLElement).scrollTop = pageCacheData.scrollTop
      })
      return true
    },
    checkRestorePageData() {
      this.poetryID = this.$route.params.id as string
      if (!this.restorePageData()) {
        this.getPoetryDetail()
      }
    },

    getPoetryDetail() {
      const setSimplePoetry = (o: any) => {
        o.praiseTotal = -1
        o.praiseComments = []
        o.isPraiseLoading = false
        o.commentTotal = -1
        o.realComments = []
        o.isCommentLoading = false
        if (o.user) {
          o.user = Object.freeze(o.user)
        }
        this.poetry = o
        this.checkPraisePoetry()
        this.getContentComments(false)
        this.getPraiseComments(false)
      }

      const temp = sessionStorage.getItem('poetry-detail')
      if (temp) {
        const o = JSON.parse(temp)
        if (this.poetryID === o.id) {
          setSimplePoetry(o)
          return
        }
        sessionStorage.removeItem('poetry-detail')
      }

      apiGetData(apiURL.poetryList, { id: this.poetryID }).then((data) => {
        setSimplePoetry(data.data)
      })
    },

    checkPraisePoetry() {
      if (!this.userID) {
        return
      }
      this.praiseRequesting = true
      apiGetData(apiURL.praiseCheck, {
        poetryId: this.poetryID
      })
        .then((resp) => {
          const { data: list = [] } = resp
          const praiseItem = list[0]
          if (!praiseItem) {
            this.myPraiseComment = undefined
            return
          }
          praiseItem.fromPoet = JSON.parse(JSON.stringify(this.selfPublicInfo))
          praiseItem.toPoet = {}
          this.myPraiseComment = praiseItem
        })
        .finally(() => {
          this.praiseRequesting = false
        })
    },

    getContentComments(isReset: boolean) {
      if (isReset) {
        this.commentOffset = 0
      }
      this.poetry.isCommentLoading = true
      apiGetData(apiURL.commentList, {
        id: this.poetryID,
        limit: this.pageLimit,
        offset: this.commentOffset
      })
        .then((resp) => {
          const { count = 0, list = [] } = resp.data

          const userIdMap = [] as any[]
          list.forEach((o: any) => {
            const toPoet = Cache.UserCache.getData(o.toId, true)
            if (toPoet) {
              o.toPoet = toPoet
            } else {
              o.toPoet = null
              userIdMap[o.toId] = true
            }

            const fromPoet = Cache.UserCache.getData(o.fromId, true)
            if (fromPoet) {
              o.fromPoet = fromPoet
            } else {
              o.fromPoet = null
              userIdMap[o.fromId] = true
            }
          })
          const userIds = Object.keys(userIdMap)
          userIds.length &&
            apiGetData(apiURL.userInfoList2, { ids: userIds.join(',') }).then((resp) => {
              const users = resp.data || []
              users.forEach((o: any) => {
                Cache.UserCache.setData(o.id, o)
              })

              list.forEach((o: any) => {
                if (!o.toPoet) {
                  o.toPoet = Cache.UserCache.getData(o.toId, true)
                }
                if (!o.fromPoet) {
                  o.fromPoet = Cache.UserCache.getData(o.fromId, true)
                }
              })
            })

          const poetry = this.poetry
          if (isReset) {
            poetry.realComments = list
          } else {
            poetry.realComments.push(...list)
          }
          poetry.commentTotal = count

          this.commentOffset += this.pageLimit
        })
        .finally(() => {
          this.poetry.isCommentLoading = false
        })
    },
    getPraiseComments(isReset: boolean) {
      if (isReset) {
        this.praiseOffset = 0
      }
      this.poetry.isPraiseLoading = true
      apiGetData(apiURL.praiseList, {
        id: this.poetryID,
        limit: this.pageLimit,
        offset: this.praiseOffset
      })
        .then((resp) => {
          const { count = [], list = [] } = resp.data

          const userIds = [] as any[]
          list.forEach((o: any) => {
            o.toPoet = {}
            const fromPoet = Cache.UserCache.getData(o.fromId)
            if (fromPoet) {
              o.fromPoet = JSON.parse(JSON.stringify(fromPoet))
            } else {
              o.fromPoet = null
              userIds.push(o.fromId)
            }
          })
          userIds.length &&
            apiGetData(apiURL.userInfoList2, { ids: userIds.join(',') }).then((resp) => {
              const users = resp.data || []
              users.forEach((o: any) => {
                Cache.UserCache.setData(o.id, o)
              })

              list.forEach((o: any) => {
                const fromPoet = Cache.UserCache.getData(o.fromId)
                o.fromPoet = JSON.parse(JSON.stringify(fromPoet))
              })
            })

          const poetry = this.poetry
          if (isReset) {
            poetry.praiseComments = list
          } else {
            poetry.praiseComments.push(...list)
          }
          poetry.praiseTotal = count

          this.praiseOffset += this.pageLimit
        })
        .finally(() => {
          this.poetry.isPraiseLoading = false
        })
    },

    openCommentInput(poetryId: string, fromId: string, tip: string) {
      if (!this.userID) {
        this.$toastLogin()
        return
      }
      this.commentVisible = true
      this.commentID = poetryId
      this.commentTypeUserID = this.poetry.poetId || this.poetry.user.id
      this.commentToID = fromId
      this.commentTip = tip
    },
    onCheckPraisePoetry(e: any) {
      if (!this.userID) {
        this.$toastLogin()
        return
      }
      // null判断表示没请求到是否点赞该诗词数据
      if (this.praiseRequesting || this.myPraiseComment === null) {
        return
      }

      this.praiseRequesting = true
      const comment = this.myPraiseComment
      if (this.isPraise) {
        apiPostData(apiURL.praiseDelete, {
          id: comment.id
        })
          .then(() => {
            const { praiseComments } = this.poetry
            const index = praiseComments.findIndex((o: any) => o.id === comment.id)
            if (index >= 0) {
              praiseComments.splice(index, 1)
              this.praiseOffset -= 1
            }
            this.poetry.praiseTotal -= 1
            this.myPraiseComment = undefined
          })
          .finally(() => {
            this.praiseRequesting = false
          })
      } else {
        const params = {
          poetryId: this.poetry.id,
          poetId: this.poetry.poetId || this.poetry.user.id
        }
        apiPostData(apiURL.praiseCreate, params)
          .then(({ data }) => {
            // TODO:
            const comment = {
              id: data.insertId,
              ...params,
              fromId: this.selfPublicInfo.id,
              createTime: ''
            } as any
            const { praiseTotal, praiseComments } = this.poetry
            if (praiseTotal === praiseComments.length) {
              comment.fromPoet = JSON.parse(JSON.stringify(this.selfPublicInfo))
              comment.itemTag = 'opacity'
              praiseComments.push(comment)
            }
            this.myPraiseComment = comment
            this.poetry.praiseTotal += 1

            this.$nextTick(() => {
              this.onPraiseAnime(e, comment)
            })
          })
          .finally(() => {
            this.praiseRequesting = false
          })
      }
    },
    deleteComment(poetry: any, comment: any) {
      const id = comment.id
      apiPostData(apiURL.commentDelete, {
        id
      }).then(() => {
        // this.getContentComments(true)
        const comments = poetry.realComments
        const index = comments.findIndex((o: any) => o.id === id)
        index !== -1 && comments.splice(index, 1)
        poetry.commentTotal -= 1
      })
    },

    handleDropdown(key: string, e: any) {
      const poetry = this.poetry
      switch (key) {
        case 'edit':
          {
            const editPoetry = {
              id: poetry.id,
              set: poetry.set,
              title: poetry.title,
              content: poetry.content,
              end: poetry.end
            }
            sessionStorage.setItem(PEOTRY.EDIT_DATA, JSON.stringify(editPoetry))
            this.$router.push({
              name: 'poetry-edit',
              params: { id: editPoetry.id }
            })
          }
          break
        case 'comment':
          {
            this.openCommentInput(poetry.id, this.userID, '请输入评论')
          }
          break
        case 'praise':
          {
            this.onCheckPraisePoetry(e)
          }
          break
        case 'delete':
          {
            this.$confirm({
              title: '删除提示',
              content: '诗词删除后将无法找回，请确认!',
              confirm: () => {
                apiPostData(apiURL.poetryDelete, {
                  userId: this.userID,
                  id: this.poetry.id
                }).then(() => {
                  this.$toast('删除成功')
                  Cache.PoetryPageCache.delete(this.poetryID)
                  Cache.OptionCache.setData(Cache.OPTION.DELETE, {
                    id: this.poetryID,
                    type: 'poetry'
                  })
                  this.onBack()
                })
              }
            })
          }
          break
        default:
          break
      }
    },
    onClickPoetry(e: any) {
      const { el, itemType } = getItemTypeObj(e.target) || {}
      if (!itemType) {
        this.menusVisible = !this.menusVisible
        return
      }

      const poetry = this.poetry
      const itemIndex = getItemIndex(el as HTMLElement)
      const commentIndex = getItemTypeIndex(el as HTMLElement, 'comment')

      switch (itemType) {
        case 'poetry-content':
          {
            const time = this.previousTime || 0
            const currentTime = Date.now()
            if (currentTime - time < 300) {
              this.onCheckPraisePoetry(e)
            }
            this.previousTime = currentTime
          }
          break
        case 'poetry-image':
          {
            this.images = (this.$refs.poetry as any).poetryImages
            this.imageIndex = itemIndex
            this.viewerVisible = true
          }
          break
        case 'poet':
          {
            this.openCommentInput(poetry.id, this.userID, '请输入评论')
          }
          break
        case 'poet-avatar':
          {
            this.$router.push({
              name: 'personal',
              query: {
                uuid: poetry.poetId || poetry.user.id,
                username: poetry.user.username
              }
            })
          }
          break
        case 'comment-avatar':
          {
            const poet = poetry.praiseComments[itemIndex].fromPoet
            this.$router.push({
              name: 'personal',
              query: { uuid: poet.id, username: poet.username }
            })
          }
          break
        case 'comment-from':
          {
            const fromComment = poetry.realComments[commentIndex]
            this.$router.push({
              name: 'personal',
              query: { uuid: fromComment.fromId }
            })
          }
          break
        case 'comment-to':
          {
            const toComment = poetry.realComments[commentIndex]
            this.$router.push({
              name: 'personal',
              query: { uuid: toComment.toId }
            })
          }
          break
        case 'comment-content':
          {
            this.onClickComment(poetry, poetry.realComments[commentIndex])
          }
          break
        case 'avatars-more':
          {
            this.getPraiseComments(false)
          }
          break
        case 'comments-more':
          {
            this.getContentComments(false)
          }
          break
        default:
          {
            this.menusVisible = !this.menusVisible
          }
          break
      }
    },
    onClickComment(poetry: any, comment: any) {
      if (!this.userID) {
        this.$toastLogin()
        return
      }
      if ('' + this.userID === '' + comment.fromId) {
        // 当前评论是当前用户创建
        this.$confirm({
          title: '提示',
          content: '是否删除该评论?',
          confirm: () => {
            this.deleteComment(poetry, comment)
          }
        })
        return
      }
      Cache.UserCache.setData(comment.fromId, comment.fromPoet)
      this.openCommentInput(comment.poetryId, comment.fromId, `回复 ${comment.fromPoet.username}`)
    },
    handleCommentOk(o: any) {
      // this.getContentComments(true)
      const { commentTotal, realComments } = this.poetry
      if (commentTotal === realComments.length) {
        apiGetData(apiURL.commentDetail, { id: o.insertId }).then((resp) => {
          const comment = resp.data[0]
          comment.fromPoet = JSON.parse(JSON.stringify(this.selfPublicInfo))
          comment.toPoet = Cache.UserCache.getData(this.commentToID)
          realComments.push(comment)
        })
      }
      this.poetry.commentTotal += 1
    },

    onPraiseAnime(e: any, data: any) {
      const poetry = this.poetry
      const instance = this.$refs.poetry as any
      const commentsEl = instance.$refs.comments
      if (!commentsEl) {
        return
      }
      const avatarsEl = commentsEl.$refs.avatars
      let tempEl = commentsEl.$el
      if (avatarsEl.children.length) {
        tempEl = avatarsEl.children[avatarsEl.children.length - 1]
      }
      const rect = tempEl.getBoundingClientRect()
      // console.log(tempEl, rect, this.$refs.anime)
      this.praiseFromStyle = {
        left: e.clientX + 'px',
        top: e.clientY + 'px'
      }
      this.praiseToStyle = {
        left: rect.left + rect.width / 2 + 'px',
        top: rect.top + rect.height / 2 + 'px'
      }
      this.praiseId = poetry.id
      this.praiseVisible = true
      ;(this.praiseMap as any)[poetry.id] = {
        poetry,
        data
      }
    },
    handleAnimeEnd(id: string) {
      const obj = (this.praiseMap as any)[id] as any
      if (!obj) {
        return
      }
      this.praiseVisible = false
      obj.data.itemTag = ''
      delete (this.praiseMap as any)[id]
    }
  }
})
</script>

<style lang="scss" scoped>
@import '@/ui/style/const.scss';

.poetry-detail {
  display: flex;
  flex-direction: column;
  position: relative;
  height: 100%;
  overflow: hidden;

  .sg-dropdown {
    display: inline-block;
    background-color: transparent;
  }

  .main {
    position: relative;
    flex: 1;
    height: 100%;
    overflow: hidden;
  }
  .main-wrapper {
    height: 100%;
    padding: 1rem 0;
    box-sizing: border-box;
    overflow-x: hidden;
    overflow-y: auto;
  }

  .right-menus {
    position: fixed;
    right: 0;
    top: 11rem;
    padding: 1rem;
    background-color: rgba($color-theme, 0.5);
    opacity: 1;
    border-radius: 1rem 0 0 1rem/1rem 0 0 1rem;
    .menu-item {
      text-align: center;
      color: white;
    }
    .menu-item + .menu-item {
      margin-top: 1.5rem;
    }
    .iconfont {
      font-size: 2rem;
    }
    .is-praise .icon-like {
      color: $color-theme;
    }
  }
  .slide-enter,
  .slide-leave-to {
    right: -5rem;
    opacity: 0;
  }
  .slide-enter-active,
  .slide-leave-active {
    transition:
      opacity 0.3s ease,
      right 0.3s ease;
  }
}
</style>
